/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.mygameframework.util;

import com.mygameframework.sprite.AbstractSprite;
import com.mygameframework.sprite.Animation;
import com.mygameframework.test.GirlSprite;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;

/**
 *
 * @author bill
 */
public class Utility {

    private static Map<String, Image> imgs = new HashMap<String, Image>();
    
    static GraphicsEnvironment env=GraphicsEnvironment.getLocalGraphicsEnvironment();
    
    
    
//    public int[] getAlphaBand(BufferedImage img){
//        int w=img.getWidth();
//        int h=img.getHeight();
//        int[] data=new int[w*h];
//        WritableRaster r=img.getAlphaRaster();
//        return r.getPixels(0, 0, w, h, data);
//    }
//    public int[] getRGB(BufferedImage img){
//        
//        int w=img.getWidth();
//        int h=img.getHeight();
//        int[] data=new int[w*h];
//        return img.getRGB(0, 0, w, h, data,0  , w);
//    }
    /***
     * 
     * @param img
     * @param cSearch 必须是24位的rgb
     * @param cReplace 必须是32位的argb
     * @return  兼容的(透明能力的)图像
     */
    public static BufferedImage replaceColor(BufferedImage img,int cSearch,int cReplace){
        int w=img.getWidth();
        int h=img.getHeight();
        int[] src=img.getRGB(0, 0, w, h, null, 0, w);
        int[] dst=new int[src.length];
        int[] alphaDst=new int[src.length];
        int a=(cReplace>>24)&0xFF;
        for(int i=0;i<src.length;i++){
            
            if( (src[i]&0x00FFFFFF) ==cSearch){
                dst[i]=cReplace & 0x00FFFFFF;
                alphaDst[i]= a;
            }else{
                dst[i]=src[i];
                alphaDst[i]=(src[i]>>24)&0xFF;
            }
        }
        BufferedImage result=createCompatibleImage(w, h, Transparency.TRANSLUCENT);
        result.setRGB(0, 0, w, h, dst, 0, w);
        result.getAlphaRaster().setPixels(0, 0, w, h, alphaDst);
        return result;
    }
//    static GraphicsDevice defaultDevive =env.getDefaultScreenDevice();
//    static GraphicsConfiguration config=defaultDevive.getDefaultConfiguration();
//    static Toolkit toolkit=Toolkit.getDefaultToolkit();
    /***
     * 
     * @param w
     * @param h
     * @param transparency Transparency.OPAQUE ...
     * @return 
     */
    public static BufferedImage createCompatibleImage(int w,int h,int transparency){
        return  getGraphicsConfiguration().createCompatibleImage(w, h, transparency);
    }
    public static BufferedImage createCompatibleImage(int w,int h){
        return getGraphicsConfiguration().createCompatibleImage(w, h);
    }
    /**没硬设备(屏幕)支持则返回ture */
    private static boolean isHeadless(){
        return env. isHeadless();
    }
        // Returns the graphics configuration for the primary screen
    private static GraphicsConfiguration getGraphicsConfiguration() {
        return GraphicsEnvironment.getLocalGraphicsEnvironment().
                    getDefaultScreenDevice().getDefaultConfiguration();
    }
    
    public BufferedImage toBufferedImage(Image oldImg){
        if(oldImg instanceof BufferedImage) return (BufferedImage) oldImg;
        BufferedImage bimg=getGraphicsConfiguration()
                .createCompatibleImage(oldImg.getWidth(null),
                oldImg.getHeight(null), Transparency.TRANSLUCENT);
        Graphics g=bimg.getGraphics();
        g.drawImage(oldImg, 0,0, null);
        g.dispose();
        return bimg;
    }
    public boolean isCompatible(BufferedImage img){
        return getGraphicsConfiguration().getColorModel()
                .equals(img.getColorModel());
    }
        /**
     * 返回硬兼容图像
     * <p>Return a new compatible image that contains a copy of the specified
     * image. This method ensures an image is compatible with the hardware,
     * and therefore optimized for fast blitting operations.</p>
     *
     * <p>If the method is called in a headless environment, then the returned
     * <code>BufferedImage</code> will be the source image.</p>
     *
     * @see #createCompatibleImage(java.awt.image.BufferedImage)
     * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int)
     * @see #createCompatibleImage(int, int)
     * @see #createCompatibleTranslucentImage(int, int)
     * @see #loadCompatibleImage(java.net.URL)
     * @param image the image to copy into a new compatible image
     * @return a new compatible copy, with the
     *   same width and height and transparency and content, of <code>image</code>
     */
    public static BufferedImage toCompatibleImage(BufferedImage image) {
        if (isHeadless()) {
            return image;
        }
        if (image.getColorModel().equals(
                getGraphicsConfiguration().getColorModel())) {
            return image;
        }
        BufferedImage compatibleImage =
                getGraphicsConfiguration().createCompatibleImage(
                    image.getWidth(), image.getHeight(),
                    image.getTransparency());
        Graphics g = compatibleImage.getGraphics();
        
        try {
            g.drawImage(image, 0, 0, null);
        } finally {
            g.dispose();
        }

        return compatibleImage;
    }
    /**
     * 返回与给定bufferedimage相同颜色模型的图像,但不一定与硬件兼容
     * <p>Returns a new <code>BufferedImage</code> using the same color model
     * as the image passed as a parameter. The returned image is only compatible
     * with the image passed as a parameter. This does not mean the returned
     * image is compatible with the hardware.</p>
     *
     * @param image the reference image from which the color model of the new
     *   image is obtained
     * @return a new <code>BufferedImage</code>, compatible with the color model
     *   of <code>image</code>
     */
    public static BufferedImage createColorModelCompatibleImage(BufferedImage image) {
        ColorModel cm = image.getColorModel();
        return new BufferedImage(cm,
            cm.createCompatibleWritableRaster(image.getWidth(),
                                              image.getHeight()),
            cm.isAlphaPremultiplied(), null);
    }
    /**
     * <p>Returns a new compatible image with the same width, height and
     * transparency as the image specified as a parameter. That is, the
     * returned BufferedImage will be compatible with the graphics hardware.
     * If this method is called in a headless environment, then
     * the returned BufferedImage will be compatible with the source
     * image.</p>
     *
     * @see java.awt.Transparency
     * @see #createCompatibleImage(int, int)
     * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int)
     * @see #createCompatibleTranslucentImage(int, int)
     * @see #loadCompatibleImage(java.net.URL)
     * @see #toCompatibleImage(java.awt.image.BufferedImage)
     * @param image the reference image from which the dimension and the
     *   transparency of the new image are obtained
     * @return a new compatible <code>BufferedImage</code> with the same
     *   dimension and transparency as <code>image</code>
     */
    public static BufferedImage createCompatibleImage(BufferedImage image) {
        return createCompatibleImage(image, image.getWidth(), image.getHeight());
    }
    /**
     * <p>Returns a new compatible image of the specified width and height, and
     * the same transparency setting as the image specified as a parameter.
     * That is, the returned <code>BufferedImage</code> is compatible with
     * the graphics hardware. If the method is called in a headless
     * environment, then the returned BufferedImage will be compatible with
     * the source image.</p>
     *
     * @see java.awt.Transparency
     * @see #createCompatibleImage(java.awt.image.BufferedImage)
     * @see #createCompatibleImage(int, int)
     * @see #createCompatibleTranslucentImage(int, int)
     * @see #loadCompatibleImage(java.net.URL)
     * @see #toCompatibleImage(java.awt.image.BufferedImage)
     * @param width the width of the new image
     * @param height the height of the new image
     * @param image the reference image from which the transparency of the new
     *   image is obtained
     * @return a new compatible <code>BufferedImage</code> with the same
     *   transparency as <code>image</code> and the specified dimension
     */
    public static BufferedImage createCompatibleImage(BufferedImage image,
                                                      int width, int height) {
        return isHeadless() ?
                new BufferedImage(width, height, image.getType()) :
                getGraphicsConfiguration().createCompatibleImage(width, height,
                                                   image.getTransparency());
    }
    public static BufferedImage copyImage(BufferedImage img){
            BufferedImage copy=createColorModelCompatibleImage(img);
            Graphics g=copy.getGraphics();
            g.drawImage(img, 0, 0, null);
            g.dispose();
            return copy;
    }
    public static BufferedImage loadBufferedImage(String name) throws IOException{
        return ImageIO.read(getURL(name));
    }
    /**
     * 加截硬件兼容的图像
     * @param name name is a String sample as "images/**.gif"
     * @return
     * @throws java.io.IOException
     */
    public synchronized static BufferedImage getCompatibleBufferedImage(String name) throws IOException {
        if (imgs.get(name) == null) {
            BufferedImage img = ImageIO.read(getURL(name));
             //TODO 发布是去掉
            if(img.getWidth()<=0) throw new IOException();
            System.out.println("``````````````````````");
            System.out.println("name: "+name);
               System.out.println(img.getColorModel());
               System.out.println(img.getRaster());
               System.out.println(toCompatibleImage(img).getColorModel());
               System.out.println(toCompatibleImage(img).getRaster());
               
            imgs.put(name, toCompatibleImage(img));
            System.out.println("ss");
            imgs.put(name, img);
        }
        return (BufferedImage) imgs.get(name);
    }
    /**
     * the path of file can be both absolute and relative 
     * example:images/a.png   or c:/images/a.png 
     */
    public static URL getURL(String name) {
        URL url = Thread.currentThread().getContextClassLoader().getResource(name);
        if(url==null){
            File f=new File(name);
            try {
                url=f.toURI().toURL();
            } catch (MalformedURLException ex) {
                Logger.getLogger(Utility.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return url;
    }

    /**
     * Convenience method that returns a scaled instance of the
     * provided BufferedImage.
     *
     *
     * @param img the original image to be scaled
     * @param targetWidth the desired width of the scaled instance,
     *    in pixels
     * @param targetHeight the desired height of the scaled instance,
     *    in pixels
     * @param hint one of the rendering hints that corresponds to
     *    RenderingHints.KEY_INTERPOLATION (e.g.
     *    RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR,
     *    RenderingHints.VALUE_INTERPOLATION_BILINEAR,
     *    RenderingHints.VALUE_INTERPOLATION_BICUBIC)
     * @param progressiveBilinear if true, this method will use a multi-step
     *    scaling technique that provides higher quality than the usual
     *    one-step technique (only useful in down-scaling cases, where
     *    targetWidth or targetHeight is
     *    smaller than the original dimensions)
     * @return a scaled version of the original BufferedImage
     */
    public static BufferedImage getFasterScaledInstance(BufferedImage img,
            int targetWidth, int targetHeight, Object hint,
            boolean progressiveBilinear) {
        int type = (img.getTransparency() == Transparency.OPAQUE) ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
        BufferedImage ret = img;
        BufferedImage scratchImage = null;
        Graphics2D g2 = null;
        int w, h;
        int prevW = ret.getWidth();
        int prevH = ret.getHeight();
        boolean isTranslucent = img.getTransparency() != Transparency.OPAQUE;

        if (progressiveBilinear) {
            // Use multi-step technique: start with original size, then
            // scale down in multiple passes with drawImage()
            // until the target size is reached
            w = img.getWidth();
            h = img.getHeight();
        } else {
            // Use one-step technique: scale directly from original
            // size to target size with a single drawImage() call
            w = targetWidth;
            h = targetHeight;
        }

        do {
            if (progressiveBilinear && w > targetWidth) {
                w /= 2;
                if (w < targetWidth) {
                    w = targetWidth;
                }
            }

            if (progressiveBilinear && h > targetHeight) {
                h /= 2;
                if (h < targetHeight) {
                    h = targetHeight;
                }
            }

            if (scratchImage == null || isTranslucent) {
                // Use a single scratch buffer for all iterations
                // and then copy to the final, correctly-sized image
                // before returning
                scratchImage = new BufferedImage(w, h, type);
                g2 = scratchImage.createGraphics();
            }
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
            g2.drawImage(ret, 0, 0, w, h, 0, 0, prevW, prevH, null);
            prevW = w;
            prevH = h;

            ret = scratchImage;
//            System.out.println(w+" "+h);
        } while (w != targetWidth || h != targetHeight);

        if (g2 != null) {
            g2.dispose();
        }

        // If we used a scratch buffer that is larger than our target size,
        // create an image of the right size and copy the results into it
        if (targetWidth != ret.getWidth() || targetHeight != ret.getHeight()) {
//            System.out.println("but "+ret.getWidth()+" "+ret.getHeight());
            scratchImage = new BufferedImage(targetWidth, targetHeight, type);
            g2 = scratchImage.createGraphics();
            g2.drawImage(ret, 0, 0, null);
            g2.dispose();
            ret = scratchImage;
        }

        return ret;
    }

    /**
     *
     * @param image
     * @param percent 倒影是原图像的高的百分比 float
     * @return
     */
    public static BufferedImage createReflection(BufferedImage image, float percent) {
        int height = image.getHeight();
        int heightN = (int) (height * (1 + percent));
        BufferedImage result = new BufferedImage(image.getWidth(), heightN,
                BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = result.createGraphics();

        // Paints original image
        g2.drawImage(image, 0, 0, null);

        // Paints mirrored image
        g2.scale(1.0, -1.0);
        g2.drawImage(image, 0, -height - height, null);
        g2.scale(1.0, -1.0);
        // Move to the origin of the clone
        g2.translate(0, height);

        // Creates the alpha mask
        GradientPaint mask;
        mask = new GradientPaint(0, 0, new Color(1.0f, 1.0f, 1.0f, 0.4f),
                0, height * percent, new Color(1.0f, 1.0f, 1.0f, 0.0f));
        Paint oldPaint = g2.getPaint();
        g2.setPaint(mask);

        // Sets the alpha composite
        g2.setComposite(AlphaComposite.DstIn);

        // Paints the mask
        g2.fillRect(0, 0, image.getWidth(), height);

        g2.dispose();
        return result;
    }
    public static Animation getAnimation(Animation anim,String[] paths,
            int[] intervals,String des) throws IOException {
        Animation a=anim;
        a.setDescription(des);
        for(int i=0;i<paths.length;i++){
            Image frame=getCompatibleBufferedImage(paths[i]);
            a.addFrame(frame, intervals[i]);
        }
        return a;
    }
    public static AbstractSprite getActor() throws IOException {
        Map<Integer,Animation> anims = new HashMap<Integer,Animation>();
        int[] intervals={
            200,200,200,200
        };
        String[] b = {
            "E:/rpgm/m/b/b1.png",
            "E:/rpgm/m/b/b2.png",
            "E:/rpgm/m/b/b3.png",
            "E:/rpgm/m/b/b4.png"
        };
        String[] t = {
            "E:/rpgm/m/t/t1.png",
            "E:/rpgm/m/t/t2.png",
            "E:/rpgm/m/t/t3.png",
            "E:/rpgm/m/t/t4.png"
        };
        String[] r = {
            "E:/rpgm/m/r/r1.png",
            "E:/rpgm/m/r/r2.png",
            "E:/rpgm/m/r/r3.png",
            "E:/rpgm/m/r/r4.png"
        };
        String[] l = {
            "E:/rpgm/m/l/l1.png",
            "E:/rpgm/m/l/l2.png",
            "E:/rpgm/m/l/l3.png",
            "E:/rpgm/m/l/l4.png"
        };
        Animation t_a=new Animation.Looped();
        anims.put(GirlSprite.DIR_TOP, getAnimation(t_a, t, intervals, "上"));
        Animation r_a=new Animation.Looped();
        anims.put(GirlSprite.DIR_TOP, getAnimation(r_a, r, intervals, "右"));
        Animation b_a=new Animation.Looped();
        anims.put(GirlSprite.DIR_TOP, getAnimation(b_a, b, intervals, "下"));
        Animation l_a=new Animation.Looped();
        anims.put(GirlSprite.DIR_TOP, getAnimation(l_a, l, intervals, "左"));
        AbstractSprite g = new GirlSprite(anims);
        
        return g;
    }
    public static void main(String[] args) throws MalformedURLException, IOException {
        URL u=getURL("file:/E:/rpgm/m/b/b1.png");
        File f=new File("E:/rpgm/m/b/b1.png");
        System.out.println(u);
//        Image a=getBufferedImage("E:/rpgm/m/b/b1.png");
        Image a=getCompatibleBufferedImage("images/player1.png");
        System.out.println(a.getWidth(null));
        System.out.println(f.toURI().toURL());
        System.out.println(f.toURL());
        AbstractSprite s=getActor();
        s.getAnimations().size();
        s.getAnimations().get(0).getCurrFrame().getFrameWidth();
        System.out.println(s.getAnimations().get(0).getCurrFrame().getFrameWidth());
    }
    
}
